#pragma once

#include "typedef.h"
#include "error.h"
#include "sysapi.h"
#include "IObject.h"
#include "IInterface.h"

SYS_BEGIN()
//////////////////////////////////////////////////////////////////////////
//object define
template<class BASE>
class Object : public BASE,public IObject
{
public:
	enum{CLSID_CLS=BASE::CLSID_CLS};
	static vresult CreateMe(vclsid cls,IObject** ppObject)
	{
		if(CLSID_CLS!=cls)
			return err_notregistered;
		*ppObject=new Object<BASE>();
		return vok;
	}

public:
	virtual vresult ReleaseObject()
	{
		if(m_refcount==0)
		{
			delete this;
			return vok;
		}
		ASSERT(false);
		return err_reflocked;
	}
	virtual vresult QueryVInterface(viid iid,IInterface** ppV) { return BASE::DoQueryInterface(iid,ppV);}
	virtual vclsid GetClassID() { return CLSID_CLS;}
	virtual bool IsObjectLocked() { return m_refcount!=0;}
	virtual void IncInterfaceRef(){++m_refcount;}
	virtual void DecInterfaceRef(){--m_refcount;}
	virtual vresult QueryObject(IObject** ppObject) { *ppObject=static_cast<IObject*>(this); return vok;}

protected:	
	Object() : m_refcount(0){}

private:
	long m_refcount;
};

//////////////////////////////////////////////////////////////////////////
//module object define
template<class BASE>
class GlobalObject : public BASE,public IObject
{
public:
	enum{CLSID_CLS=BASE::CLSID_CLS};
	static vresult CreateMe(vclsid cls,IObject** ppObject)
	{
		*ppObject=NULL;
		if(CLSID_CLS!=cls)
			return err_notregistered;
		GlobalObject<BASE>* pObject=new GlobalObject<BASE>();
		*ppObject=pObject;
		return vok;
	}

public:
	virtual vresult ReleaseObject(){ return vok; }
	virtual vresult QueryVInterface(viid iid,IInterface** ppV){ return BASE::DoQueryInterface(iid,ppV); }
	virtual vclsid GetClassID(){return CLSID_CLS;}
	virtual bool IsObjectLocked(){ return true;}

	virtual void IncInterfaceRef(){}
	virtual void DecInterfaceRef(){}
	virtual vresult QueryObject(IObject** ppObject) { *ppObject=static_cast<IObject*>(this); return vok;}

protected:	
	GlobalObject(){}
	virtual ~GlobalObject(){}
};

//////////////////////////////////////////////////////////////////////////
//null object
template<class IF_Type>
class NullObject : public IF_Type
{
public:
	virtual void IncInterfaceRef(){}
	virtual void DecInterfaceRef(){}
	virtual vresult QueryObject(IObject** ppObject) { *ppObject=NULL;return err_nullobject; }
};
//////////////////////////////////////////////////////////////////////////
//null object
template<class BASE>
class SingletonObject : public GlobalObject<BASE>
{
	enum{CLSID_CLS=BASE::CLSID_CLS};

public:
	static vresult CreateMe(vclsid cls,IObject** ppObject)
	{
		*ppObject = NULL;
		if(CLSID_CLS!=cls)
			return err_notregistered;
		static SingletonObject<BASE>* singleton =NULL;
		if(!singleton)
			singleton = new SingletonObject<BASE>();
		*ppObject=singleton;
		return vok;
	}
protected:	//must be heap object
	SingletonObject(){}
	virtual ~SingletonObject(){}
};

//////////////////////////////////////////////////////////////////////////
//stack object
template<class BASE>
class StackObject : public Object<BASE>
{
	enum{CLSID_CLS=BASE::CLSID_CLS};
	DONT_NEW()
public:
	StackObject(){}
	~StackObject(){}

	virtual vresult ReleaseObject() { return vok; }
	virtual vresult QueryVInterface(viid iid,IInterface** ppV) { return BASE::DoQueryInterface(iid,ppV); }
	virtual vclsid GetClassID() { return CLSID_CLS;}
	virtual bool IsObjectLocked() { return true;}

	virtual void IncInterfaceRef(){}
	virtual void DecInterfaceRef(){}
	virtual vresult QueryObject(IObject** ppObject) { *ppObject=static_cast<IObject*>(this); return vok;}
};

//////////////////////////////////////////////////////////////////////////
//
struct auto_register_assistant{
	auto_register_assistant(vclsid clsid,CreateObjectFuncPtr func){
		::RegisterCreator(clsid,func);
	}
};

template<typename T>
inline IObject* getSelf(void* obj)
{
	IObject* self = NULL;
	T* pIF = (T*)obj;
	pIF->QueryObject(&self);
	return self;
}
SYS_END()